<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <h1>字节面试题-并发任务控制</h1>
    <script>
      function timeout(time) {
        return new Promise((reslove) => setTimeout(reslove, time));
      }

      class SuperTask {
        constructor() {
          // 存放任务队列
          this.tasks = [];
          // 并发数量
          this.concurrency = 2;
          // 当前在运行的任务数量
          this.runningCount = 0;
        }

        add(fun) {
          return new Promise((reslove, reject) => {
            this.tasks.push({
              callback: fun,
              reslove,
              reject,
            });
            this._run2();
          });
        }

        // 运行任务的函数 == 方式 1（递归）
        async _run() {
          // 判断是否需要排队，还是直接可以运行
          if (this.runningCount < this.concurrency && this.tasks.length) {
            const task = this.tasks.shift();
            try {
              // 直接运行
              this.runningCount++;
              await task.callback();
              task.reslove();
              this.runningCount--;
              this._run();
            } catch (e) {
              console.log("running task err", e);
              task.reject(e);
              this.runningCount--;
            }
          }
        }

        // 运行任务的函数 == 方式 2（while 循环）
        async _run2() {
          while (this.runningCount < this.concurrency && this.tasks.length) {
            // 直接运行
            const task = this.tasks.shift();
            try {
              this.runningCount++;
              await task.callback();
              task.reslove();
              this.runningCount--;
            } catch (e) {
              this.runningCount--;
              task.reject(e);
              console.log("running task err", e);
            }
          }
        }
      }

      const superTask = new SuperTask();
      function addTask(time, name) {
        superTask
          .add(() => timeout(time))
          .then(() => {
            console.log(`任务${name}完成`);
          });
      }
      addTask(10000, 1); // 10000ms后输出：任务 1 完成
      addTask(5000, 2); // 5000ms后输出：任务 2 完成
      addTask(3000, 3); // 8000ms后输出：任务 3 完成
      addTask(4000, 4); // 12000ms后输出：任务 4 完成
      addTask(5000, 5); // 15000ms后输出：任务 5 完成
    </script>
  </body>
</html>
